﻿using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
//using Microsoft.Extensions.Logging;
using NLog;
using NLog.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ZxZOnlineExam.Dtos.Question;
using ZxZOnlineExam.IService;
using ZxZOnlineExam.Models;
using ZxZOnlineExam.WebApi.Tools.Pagination;

namespace ZxZOnlineExam.WebApi.Controllers
{
    /// <summary>
    /// Question控制器中包括了所有的QuestionOption操作
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]
    public class QuestionController : ControllerBase
    {
        private readonly ILogger _logger;
        private readonly IQuestionService _questionService;
        private readonly IQuestionOptionService _questionOptionService;
        private readonly IMapper _mapper;
        private List<string> _questionTypes { get; set; } = new List<string>();

        public QuestionController(IQuestionService questionService, IQuestionOptionService questionOptionService, IMapper mapper/*, NLog.Logger logger*/)
        {
            //_logger = logger;
            _logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
            _questionService = questionService;
            _questionOptionService = questionOptionService;
            _mapper = mapper;

            List<string> questionTypes = new List<string>() { 
                QuestionType.FillInTheBlank.ToString(), 
                QuestionType.MultipleChoice.ToString(), 
                QuestionType.QuestionAndAnswer.ToString(), 
                QuestionType.SingleChoice.ToString() 
            };
            _questionTypes.AddRange(questionTypes);


            _logger.Debug("NLog injected into QuestionController");
        }

        #region Get
        /// <summary>
        /// Get single by id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("{id}", Name = "GetSingleAsync")]
        public async Task<IActionResult> GetSingleAsync([FromRoute] Guid id)
        {
            var result = await _questionService.GetSingleAsync(id);
            if (result == null)
            {
                return NotFound();
            }
            var resultDto = _mapper.Map<QuestionDto>(result);
            _logger.Info("查询到了指定信息");
            return Ok(resultDto);
        }

        /// <summary>
        /// Get by query
        /// </summary>
        /// <param name="questionDtoForQuery"></param>
        /// <returns></returns>
        [HttpGet("query")]
        public async Task<IActionResult> GetByQuery([FromQuery] QuestionDtoForQuery questionDtoForQuery)
        {
            var result = (await _questionService.GetAsync()).AsQueryable();
            
            if (_questionTypes.Contains(questionDtoForQuery.QuestionType))
            {
                //等价于
                //string.IsNullOrEmpty(questionDtoForQuery.QuestionType);
                result = result.Where(r => r.QuestionType == questionDtoForQuery.QuestionType);
            }
            if (questionDtoForQuery.SubjectId.ToString() != null && questionDtoForQuery.SubjectId.ToString() != "")
            {
                result = result.Where(r => r.SubjectId == questionDtoForQuery.SubjectId);
            }
            if (questionDtoForQuery.Title != null && questionDtoForQuery.Title != "")
            {
                result = result.Where(r => r.Title.Contains(questionDtoForQuery.Title));
            }
            return Ok(_mapper.Map<List<QuestionDto>>(result.ToList()));
        }

        /// <summary>
        /// Get by query and paged
        /// </summary>
        /// <param name="questionDtoForQuery"></param>
        /// <returns></returns>
        [HttpGet("queryAndPaged")]
        public async Task<IActionResult> GetByQueryAndPaged(
            [FromQuery] QuestionDtoForQuery questionDtoForQuery,
            [FromBody] Pagination pagination)
        {
            //先查找
            var result = (await _questionService.GetAsync()).AsQueryable();
            if (_questionTypes.Contains(questionDtoForQuery.QuestionType))
            {
                result = result.Where(r => r.QuestionType == questionDtoForQuery.QuestionType);
            }
            if (questionDtoForQuery.SubjectId.ToString() != null && questionDtoForQuery.SubjectId.ToString() != "")
            {
                result = result.Where(r => r.SubjectId == questionDtoForQuery.SubjectId);
            }
            if (questionDtoForQuery.Title != null && questionDtoForQuery.Title != "")
            {
                result = result.Where(r => r.Title.Contains(questionDtoForQuery.Title));
            }
            //再分页
            pagination.Total = result.Count();
            pagination.Data = _mapper.Map<List<QuestionDto>>(
                result.Skip((pagination.PageIndex - 1) * pagination.PageSize).Take(pagination.PageSize).ToList()
                );
            return Ok(pagination);
        }
        #endregion

        #region Create
        /// <summary>
        /// Create Single
        /// </summary>
        /// <param name="questionDtoForCreation"></param>
        /// <returns></returns>
        [HttpPost]
        //[Authorize(Roles ="Admin,Teacher")]
        public async Task<IActionResult> Create([FromBody] QuestionDtoForCreation questionDtoForCreation)
        {
            //1.先创建一个QuestionOption对象
            var questionOption = _mapper.Map<QuestionOption>(questionDtoForCreation);

            //2.创建Question
            var question = _mapper.Map<Question>(questionDtoForCreation);
            question.QuestionOptionId = questionOption.Id;
            //3.保存创建的对象
            var result = await _questionOptionService.CreateAsync(questionOption) && await _questionService.CreateAsync(question);
            if (!result)
            {
                return BadRequest("服务器错误，创建失败！");
            }
            return CreatedAtRoute(nameof(GetSingleAsync), new { id = question.Id }, _mapper.Map<QuestionDto>(question));
        }

        /// <summary>
        /// Create Multiple
        /// </summary>
        /// <param name="questionDtoForCreation"></param>
        /// <returns></returns>
        [HttpPost("multiple")]
        //[Authorize(Roles ="Admin,Teacher")]
        public async Task<IActionResult> CreateMultiple([FromBody] List<QuestionDtoForCreation> questionDtoForCreations)
        {
            var result = true;
            foreach (var item in questionDtoForCreations)
            {
                //1.先创建一个QuestionOption对象
                var questionOption = _mapper.Map<QuestionOption>(item);

                //2.创建Question
                var question = _mapper.Map<Question>(item);
                question.QuestionOptionId = questionOption.Id;
                //3.保存创建的对象
                result = result && (await _questionOptionService.CreateAsync(questionOption) && await _questionService.CreateAsync(question));
            }

            if (!result)
            {
                return BadRequest("服务器错误，创建失败！");
            }
            return Ok("操作成功");
        }

        #endregion

        #region Delete
        /// <summary>
        /// Delete Single by id
        /// </summary>
        /// <returns></returns>
        [HttpDelete("{id}")]
        [Authorize(Roles = "Admin,Teacher")]
        public async Task<IActionResult> Delete([FromRoute] Guid id)
        {
            //判断要删除的对象是否存在
            var isExist = await _questionService.IsExsitedAsync(id);
            if (!isExist)
            {
                return NotFound("未找到指定对象");
            }
            //删除对象,删除Question对象时就该一并删除其对应的QuestionOption
            var result = true;
            //此处为假删除
            var question = await _questionService.GetSingleAsync(id);
            //var questionOption = await _questionOptionService.GetSingleAsync(question.QuestionOptionId);
            //question.IsRemoved = true;
            //questionOption.IsRemoved = true;
            result = result && (await _questionService.FakeDeleteAsync(id) && await _questionOptionService.FakeDeleteAsync(question.QuestionOptionId));
            if (!result)
            {
                return BadRequest("服务器错误，删除失败！");
            }
            return Ok();
        }

        /// <summary>
        /// Delete Multiple
        /// </summary>
        /// <returns></returns>
        [HttpDelete("multiple")]
        [Authorize(Roles = "Admin,Teacher")]
        public async Task<IActionResult> DeleteMultiple([FromBody] List<Guid> ids)
        {
            var result = true;
            foreach (var item in ids)
            {
                var isExist = await _questionService.IsExsitedAsync(item);
                if (!isExist)
                {
                    return NotFound("未找到指定对象");
                }
                //删除对象,删除Question对象时就该一并删除其对应的QuestionOption
                //此处为假删除
                var question = await _questionService.GetSingleAsync(item);
                //var questionOption = await _questionOptionService.GetSingleAsync(question.QuestionOptionId);
                //question.IsRemoved = true;
                //questionOption.IsRemoved = true;
                result = result && (await _questionService.FakeDeleteAsync(item) && await _questionOptionService.FakeDeleteAsync(question.QuestionOptionId));
            }
            if (!result)
            {
                return BadRequest("服务器错误，创建失败！");
            }
            return Ok("操作成功");
        }

        /// <summary>
        /// RealDelete by id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("real/{id}")]
        [Authorize(Roles ="Admin")]
        public async Task<IActionResult> RealDelete([FromRoute]Guid id)
        {
            //1.判断是否存在
            var isExist = await _questionService.IsExsitedAsync(id);
            if (!isExist)
            {
                return NotFound("未找到指定对象！");
            }
            //2.进行删除
            var result = await _questionService.RealDeleteAsync(id);
            if (!result)
            {
                return BadRequest("服务器错误，删除失败！");
            }
            return Ok();
        }


        /// <summary>
        /// RealDelete multiple
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("real")]
        [Authorize(Roles = "Admin")]
        public async Task<IActionResult> RealDeleteMultiple([FromBody] List<Guid> ids)
        {
            var result=true;
            foreach (var item in ids)
            {
                //1.判断是否存在
                var isExist = await _questionService.IsExsitedAsync(item);
                if (!isExist)
                {
                    return NotFound("未找到指定对象！");
                }
                //2.进行删除
                result = result&& await _questionService.RealDeleteAsync(item);
                
            }
            if (!result)
            {
                return BadRequest("服务器错误，删除失败！");
            }
            return Ok();
        }
        #endregion

        #region Update

        [HttpPut("{id}")]
        public async Task<IActionResult> Update([FromRoute]Guid id,[FromBody]QuestionDtoForUpdate questionDtoForUpdate)
        {
            //1.找到指定对象
            var isExist = await _questionService.IsExsitedAsync(id);
            if (!isExist)
            {
                return NotFound("未找到指定对象！");
            }
            //2.更新信息
            var question = await _questionService.GetSingleAsync(id);
              //更改Question信息
            question.SubjectId = questionDtoForUpdate.SubjectId;
            question.QuestionType = questionDtoForUpdate.QuestionType;
            question.Title = questionDtoForUpdate.Title;
            question.UpdateTime = DateTime.UtcNow;
            //更改QuestionOption信息:此处不通过AutoMapper实现，因为Dto没有传回CreateTime等内容，强行使用AutoMapper会导致时间发生变化，故使用传统方法，找到再改
            var questionOption = await _questionOptionService.GetSingleAsync(question.QuestionOptionId);
            questionOption.CorrectAnswer = questionDtoForUpdate.CorrectAnswer;
            questionOption.OptionA = questionDtoForUpdate.OptionA;
            questionOption.OptionB = questionDtoForUpdate.OptionB;
            questionOption.OptionC = questionDtoForUpdate.OptionC;
            questionOption.OptionD = questionDtoForUpdate.OptionD;
            questionOption.OptionE = questionDtoForUpdate.OptionE;

            //3.执行修改
            var result = true;
            result = result && (await _questionService.UpdateAsync(question)) && (await _questionOptionService.UpdateAsync(questionOption));
            if (!result)
            {
                return BadRequest("服务器错误，删除失败！");
            }
            return Ok(_mapper.Map<QuestionDto>(await _questionService.GetSingleAsync(id)));
        }

        #endregion
    }
}
